/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package genomemap.model;

import com.google.common.collect.ImmutableList;
import commons.core.OrderModel;
import commons.core.Singletons;
import org.apache.commons.lang.builder.ToStringBuilder;

import java.util.Collections;
import java.util.List;

/**
 * It is a model of recombination as explained in the paper Tewari, Arnold and Bhandarkar JBCB 2008.
 * <p> Unless otherwise specified, in all the methods of this class {@code null} arguments throw
 * {@code NullPointerException}.
 *
 * @author Susanta Tewari
 * @since Jul 30, 2011
 */
public class TAB08 implements OrderModel<String, TAB08> {

    /** Field description */
    private final ImmutableList<String> genes;

    /* exchange probability */

    /** Field description */
    private final ImmutableList<Double> exchangeProbs;

    /**
     * Creates a model with the default exchange probability of 0.01 for each interval.
     *
     * @param genes genes in their specified order under this model
     */
    public TAB08(final List<String> genes) {
        this(genes, Collections.nCopies(genes.size() - 1, 0.01));
    }

    /**
     * @param genes genes under study in their specified order
     * @param exchangeProbs exchange probability for each genetic interval
     */
    @SuppressWarnings("TypeMayBeWeakened")
    public TAB08(final List<String> genes, final List<Double> exchangeProbs) {


        // throw null pointer
        if (genes == null) {
            throw new NullPointerException("argument genes is null");
        }

        if (exchangeProbs == null) {
            throw new NullPointerException("argument exchangeProbs is null");
        }


        // size of genes must be atleast 2
        if (genes.size() < 2) {

            throw new IllegalArgumentException("number of genes should be at least 2 (found: "
                                               + genes.size() + ").");
        }


        // check invariant exchange-probe length = loci -1
        if (exchangeProbs.size() != (genes.size() - 1)) {
            throw new IllegalArgumentException("");
        }


        // store information
        this.genes         = ImmutableList.copyOf(genes);
        this.exchangeProbs = ImmutableList.copyOf(exchangeProbs);
    }

    /**
     * Creates a new instance of model using the current instance and the specified parameters.
     *
     * @param exchangeProbs new exchange probabilities between the consecutive genes under this
     * model
     * @return a new instance of the model
     */
    public TAB08 create(final List<Double> exchangeProbs) {
        return new TAB08(genes, exchangeProbs);
    }

    /**
     * Creates a new instance of the model from s a specified subset of genes.
     *
     * @param subGenes sub set of genes from this model
     * @return a new instance of model with the specified sub set of genes
     */
    @Override
    public TAB08 newOrder(final List<String> subGenes) {

        /* Field description */
        final double default_exchange_prob = 0.1;

        return new TAB08(subGenes, Collections.nCopies(subGenes.size() - 1, default_exchange_prob));
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public ImmutableList<String> getGenes() {
        return genes;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    @Override
    public ImmutableList<String> getOrder() {
        return genes;
    }

    /**
     * Returns the number of genes in the model.
     *
     * @return the number of genes in the model.
     */
    public int getLoci() {
        return genes.size();
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public ImmutableList<Double> getExchangeProbs() {
        return exchangeProbs;
    }

    /**
     * Contains information on model parameters.
     *
     * @return information on model parameters
     */
    @Override
    public String toString() {

        return new ToStringBuilder(this, Singletons.TO_STRING_STYLE).append("loci",
                                   getLoci()).append("genes", genes).append("xchange-probs",
                                       exchangeProbs).toString();
    }
}
